/*
 * Copyright 2011-2012 by The Regents of the University of California Licensed
 * under the Apache License, Version 2.0 (the "License"); you may not use this
 * file except in compliance with the License. you may obtain a copy of the
 * License from
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package edu.ucsd.db.bassarisk.query;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import org.apache.commons.lang3.tuple.Pair;

import edu.ucsd.db.bassarisk.exception.QueryValidationException;

public class ValidationTraversalLog {
  private final List<Exception> caughtErrors;
  private final List<Exception> caughtWarnings;
  private final List<Pair<QueryExpression, String>> exprErrors;
  private final List<Pair<QueryExpression, String>> exprWarnings;

  public ValidationTraversalLog() {
    this.exprErrors = new ArrayList<Pair<QueryExpression, String>>();
    this.exprWarnings = new ArrayList<Pair<QueryExpression, String>>();
    this.caughtErrors = new ArrayList<Exception>();
    this.caughtWarnings = new ArrayList<Exception>();
  }

  public void addError(final Exception e) {
    this.caughtErrors.add(e);
  }

  public void addError(final QueryExpression expr, final String msg) {
    this.exprErrors.add(Pair.of(expr, msg));
  }

  public void addWarning(final Exception e) {
    this.caughtWarnings.add(e);
  }

  public void addWarning(final QueryExpression expr, final String msg) {
    this.exprWarnings.add(Pair.of(expr, msg));
  }

  public Iterable<Exception> allExceptions() {
    return this.caughtErrors;
  }

  public void checkLog(final Logger LOG) throws QueryValidationException {
    if (this.hasWarnings()) {
      this.logWarnings(LOG);
    }
    if (this.hasErrors()) {
      this.logErrors(LOG);
      String message = "Query processing validation stage failed.";
      throw new QueryValidationException(message, this);
    }
  }

  public boolean hasErrors() {
    return this.exprErrors.size() > 0 || this.caughtErrors.size() > 0;
  }

  public boolean hasWarnings() {
    return this.exprWarnings.size() > 0 || this.caughtWarnings.size() > 0;
  }

  public void logErrors(final Logger log) {
    for (Pair<QueryExpression, String> pair : this.exprErrors) {
      QueryExpression op = pair.getLeft();
      String msg = "Error: [Expression %s at column %s] %s";
      log.severe(String.format(msg, op.getName(), op.getStartColumn(),
                               pair.getRight()));
    }
    for (Exception e : this.caughtErrors) {
      String msg = "Caught exception: %s\n%s";
      log.severe(String.format(msg, e.getMessage(), e.getStackTrace()));
    }
  }

  public void logWarnings(final Logger log) {
    for (Pair<QueryExpression, String> pair : this.exprWarnings) {
      QueryExpression op = pair.getLeft();
      String msg = "Error: [Expression %s at column %s.] %s";
      log.warning(String.format(msg, op.getName(), op.getStartColumn(),
                                pair.getRight()));
    }
    for (Exception e : this.caughtWarnings) {
      String msg = "Caught exception (ignored): %s\n%s";
      log.warning(String.format(msg, e.getMessage(), e.getStackTrace()));
    }
  }
}